/*

4 * 描          述:  <描述>
 * 修  改   人:  Administrator
 * 修改时间:  2020年3月12日
 * <修改描述:>
 */
package com.tx.component.file.controller;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.ui.ModelMap;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.servlet.HandlerMapping;

import com.tx.component.file.catalog.VitualFileCatalog;
import com.tx.component.file.context.FileContext;
import com.tx.component.file.resource.FCResource;
import com.tx.component.file.util.FileContextUtils;
import com.tx.core.remote.RemoteResult;
import com.tx.core.util.JsonUtils;

/**
 * 文件容器<br/>
 *   // contentType: https://tool.oschina.net/commons/
 * <功能详细描述>
 * 
 * @author  Administrator
 * @version  [版本号, 2020年3月12日]
 * @see  [相关类/方法]
 * @since  [产品/模块版本]
 */
@RequestMapping("/fc")
public class FileContextController {
    
    /** 日志记录句柄 */
    private Logger logger = LoggerFactory
            .getLogger(FileContextController.class);
    
    //view实录路径中的正则表达式
    private static Pattern VIEW_PATH_PATTERN = Pattern
            .compile("^(.+?)/view/(.*)$");
    
    /**
     * 可通过该方法，自行上传具备公共写的方法<br/>
     *    文件容器提供给具备公共写权限的目录的公共上传功能，如果不具备公共写，会抛出错误.
     * <功能详细描述>
     * @param file
     * @param model
     * @return [参数说明]
     * 
     * @return FileDefinitionDetail [返回类型说明]
     * @exception throws [异常类型] [异常说明]
     * @see [类、类#方法、类#成员]
     */
    @ResponseBody
    @RequestMapping("/{catalog}/upload")
    public RemoteResult<String> upload(
            @PathVariable(value = "catalog", required = true) String catalog,
            @RequestParam(value = "relativePath", required = true) String relativePath,
            MultipartFile file, ModelMap model) {
        RemoteResult<String> result = new RemoteResult<>();
        if (file == null) {
            result = new RemoteResult<>(-1, "上传文件不能为空.");
            return result;
        }
        
        VitualFileCatalog vfc = FileContext.getEngine()
                .getVitualFileCatalog(catalog);
        if (vfc == null) {
            result = new RemoteResult<>(-1, "上传文件异常,文件目录不存在:" + catalog);
            return result;
        }
        relativePath = FileContextUtils.handleRelativePath(relativePath);
        logger.info("   --- 开始：上传文件: catalog:" + catalog + "|relativePath:"
                + relativePath);
        try (InputStream input = file.getInputStream()) {
            FCResource res = FileContext.getEngine()
                    .save(vfc, relativePath, input);
            result.setCode(0);
            result.setData(res.getRelativePath());
            return result;
        } catch (Exception e) {
            logger.error(
                    "   --- 上传文件异常: catalog:" + catalog + "|relativePath:"
                            + relativePath,
                    e);
            result = new RemoteResult<>(-1, "上传文件异常.");
            return result;
        }
    }
    
    /**
     * 下载<br/>
     * <功能详细描述>
     * @param catalog
     * @param relativePath
     * @param model
     * @return [参数说明]
     * 
     * @return RemoteResult<FileDefinitionDetail> [返回类型说明]
     * @throws IOException 
     * @exception throws [异常类型] [异常说明]
     * @see [类、类#方法、类#成员]
     */
    @ResponseBody
    @RequestMapping("/{catalog}/download")
    public void download(
            @PathVariable(value = "catalog", required = true) String catalog,
            @RequestParam(value = "relativePath", required = true) String relativePath,
            HttpServletRequest request, HttpServletResponse response,
            ModelMap model) throws IOException {
        //处理相对路径
        VitualFileCatalog vfc = FileContext.getEngine()
                .getVitualFileCatalog(catalog);
        if (vfc == null) {
            RemoteResult<String> result = new RemoteResult<>(-1,
                    "下载文件异常,文件目录不存在:" + catalog);
            try (PrintWriter out = response.getWriter()) {
                out.write(JsonUtils.toJson(result));
                out.flush();
            }
            return;
        }
        
        relativePath = FileContextUtils.handleRelativePath(relativePath);
        FCResource res = FileContext.getEngine().find(vfc, relativePath);
        try (InputStream ins = res.getInputStream();
                OutputStream os = response.getOutputStream()) {
            String contentType = "application/octet-stream";
            response.setContentType(contentType);
            
            int count = 0;
            byte[] buffer = new byte[1024 * 1024];
            while ((count = ins.read(buffer)) != -1) {
                os.write(buffer, 0, count);
            }
            os.flush();
        } catch (Exception e) {
            logger.error(
                    "   --- 下载文件异常: catalog:" + catalog + "|relativePath:"
                            + relativePath,
                    e);
            RemoteResult<String> result = new RemoteResult<>(-1, "下载文件异常.");
            try (PrintWriter out = response.getWriter()) {
                out.write(JsonUtils.toJson(result));
                out.flush();
            }
        }
    }
    
    /**
     * 将文件进行视图呈现<br/>
     * <功能详细描述>
     * @param catalog
     * @param relativePath
     * @param model
     * @return [参数说明]
     * 
     * @return View [返回类型说明]
     * @throws IOException 
     * @exception throws [异常类型] [异常说明]
     * @see [类、类#方法、类#成员]
     */
    @ResponseBody
    @RequestMapping("/{catalog}/view/**")
    public void view(
            @PathVariable(value = "catalog", required = true) String catalog,
            HttpServletResponse response, HttpServletRequest request,
            ModelMap model) throws IOException {
        //处理相对路径
        String path = request
                .getAttribute(
                        HandlerMapping.PATH_WITHIN_HANDLER_MAPPING_ATTRIBUTE)
                .toString();
        Matcher m = VIEW_PATH_PATTERN.matcher(path);
        //相对路径
        String relativePath = "";
        if (m.matches()) {
            relativePath = FileContextUtils.handleRelativePath(m.group(2));
        }
        //获取对应的文件
        VitualFileCatalog vfc = FileContext.getEngine()
                .getVitualFileCatalog(catalog);
        if (vfc == null) {
            RemoteResult<String> result = new RemoteResult<>(-1,
                    "读取文件异常,文件目录不存在:" + catalog);
            try (PrintWriter out = response.getWriter()) {
                out.write(JsonUtils.toJson(result));
                out.flush();
            }
            return;
        }
        FCResource res = FileContext.getEngine().find(vfc, relativePath);
        try (InputStream ins = res.getInputStream();
                OutputStream os = response.getOutputStream()) {
            String contentType = res.getContentType();
            if (StringUtils.isEmpty(contentType)) {
                contentType = "application/octet-stream";
            }
            response.setContentType(contentType);
            
            int count = 0;
            byte[] buffer = new byte[1024 * 1024];
            while ((count = ins.read(buffer)) != -1) {
                os.write(buffer, 0, count);
            }
            os.flush();
        } catch (Exception e) {
            logger.error(
                    "   --- 下载文件异常: catalog:" + catalog + "|relativePath:"
                            + relativePath,
                    e);
            RemoteResult<String> result = new RemoteResult<>(-1, "下载文件异常.");
            try (PrintWriter out = response.getWriter()) {
                out.write(JsonUtils.toJson(result));
                out.flush();
            }
        }
    }
}
